package com.edu.app.util.http.impl;


import com.edu.app.util.http.DataType;
import com.edu.app.util.http.HttpInterface;
import com.edu.app.util.http.exception.NotSupportDataTypeException;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

public  class OkHttpInterface implements HttpInterface {
    private static OkHttpClient okhttpClient = null;
    private static final Logger logger = LoggerFactory.getLogger(OkHttpInterface.class);

    private static OkHttpClient.Builder configureToIgnoreCertificate(OkHttpClient.Builder builder) {
        logger.warn("Ignore Ssl Certificate");
        try {
            /*Create a trust manager that does not validate certificate chains*/
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            /*Install the all-trusting trust manager*/
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            /*Create an ssl socket factory with our all-trusting manager*/
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        } catch (Exception e) {
            logger.warn("Exception while configuring IgnoreSslCertificate" + e, e);
        }
        return builder;
    }

    private static OkHttpClient.Builder configureProxy(OkHttpClient.Builder builder){
        return builder;
    }

    private Interceptor  interceptor;
    private ProxyInfo    httpProxy;

    private  OkHttpClient client() {
        if (okhttpClient  == null) {
            synchronized (OkHttpInterface.class) {
                if(okhttpClient == null) {
                    OkHttpClient.Builder builder = new OkHttpClient.Builder();
                    OkHttpInterface.configureToIgnoreCertificate(builder);

                    if (httpProxy != null) {
                        builder.proxy(httpProxy.getProxy());
                    }
                    if (interceptor != null) {
                        builder.addInterceptor(interceptor);
                    }
                    okhttpClient = builder.build();
                }
            }
        }
        return okhttpClient;
    }

    public  OkHttpInterface(Map<String,Object> config)
    {
        this.interceptor = (Interceptor) config.get("interceptor");
        this.httpProxy   = (ProxyInfo)config.get("httpproxy");
    }
    public void HttpGetAsync(String url, Map<String, Object> queries, Callback callback)
    {
        String fullUrl = constructUrl(url,queries);
        final Request request = new Request.Builder()
                .url(fullUrl)
                .get()//默认就是GET请求，可以不写
                .build();
        Call call = client( ).newCall(request);
        call.enqueue(callback);
    }

    public String HttpGetSync(String url,Map<String, Object> queries) throws IOException {
        String responseBody = "";

        String fullUrl = constructUrl(url,queries);
        Request request = new Request
                .Builder()
                .url(fullUrl)
                .build();
        Response response = null;
        try {
            response = client().newCall(request).execute();
            int status = response.code();
            if (status == 200) {
                return response.body().string();
            }
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }


    public void HttpPostAsync(String url,
                              Map<String, Object> data,
                              DataType dataType,
                              String mediaTypeStr,
                              Callback callback ) throws NotSupportDataTypeException {

        RequestBody requestBody = null;
        switch(dataType){
            case XML:
                String xml = (String)data.get("content");
                requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml);
                break;
            case JSON:
                String json = (String)data.get("content");
                requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
                break;
            case TEXT:
                MediaType mediaType = MediaType.parse(mediaTypeStr);
                String text = (String)data.get("conent");
                requestBody = RequestBody.create(mediaType, text);
                break;
            case FORM:

                FormBody.Builder fbuilder = new FormBody.Builder();
                //添加参数
                if (data != null && data.keySet().size() > 0) {
                    for (String key : data.keySet()) {
                        fbuilder.add(key,(String) data.get(key));
                    }
                }
                requestBody = fbuilder.build();

                break;
            case FILE:
                MultipartBody.Builder mpbuilder = new MultipartBody.Builder();
                //添加参数
                if (data != null && data.keySet().size() > 0) {
                    for (String key : data.keySet()) {
                        if (data.get(key) instanceof File) {
                            File file = (File) data.get(key);
                            mpbuilder.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse(mediaTypeStr), file));
                            continue;
                        }
                        mpbuilder.addFormDataPart(key, data.get(key).toString());
                    }
                    requestBody = mpbuilder.build();
                }
                break;
            default:
                throw new NotSupportDataTypeException("Not supported data type");

        }

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        client().newCall(request).enqueue(callback);

    }
    public String HttpPost (String url,
                            Map<String, Object> data,
                            DataType dataType,
                            String mediaTypeStr  ) throws  IOException,NotSupportDataTypeException {

        String responseBody = "";
        RequestBody requestBody = null;
        switch(dataType){
            case XML:
                String xml = (String)data.get("content");
                requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml);
               break;
            case JSON:
                String json = (String)data.get("content");
                requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
                break;
            case TEXT:
                MediaType mediaType = MediaType.parse(mediaTypeStr);
                String text = (String)data.get("conent");
                requestBody = RequestBody.create(mediaType, text);
                break;
            case FORM:

                FormBody.Builder fbuilder = new FormBody.Builder();
                //添加参数
                if (data != null && data.keySet().size() > 0) {
                    for (String key : data.keySet()) {
                        fbuilder.add(key,(String) data.get(key));
                    }
                }
                requestBody = fbuilder.build();

                break;
            case FILE:
                MultipartBody.Builder mpbuilder = new MultipartBody.Builder();
                //添加参数
                if (data != null && data.keySet().size() > 0) {
                    for (String key : data.keySet()) {
                        if (data.get(key) instanceof File) {
                            File file = (File) data.get(key);
                            mpbuilder.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse(mediaTypeStr), file));
                            continue;
                        }
                        mpbuilder.addFormDataPart(key, data.get(key).toString());
                    }
                    requestBody = mpbuilder.build();
                }
                break;
            default:
                throw new NotSupportDataTypeException("Not supported data type");

        }

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Response response = null;
        try {
            OkHttpClient okHttpClient = new OkHttpClient();
            response = okHttpClient.newCall(request).execute();

            if (response.isSuccessful()) {
                return response.body().string();
            }
        }   finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;



    }

    private String constructUrl(String url, Map<String, Object> queries)
    {
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        return sb.toString();
    }
}
